home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / science / ack3d.zip / ACKVIEW.ENG < prev    next >
Text File  |  1994-01-09  |  16KB  |  596 lines

  1. /******************* ( Animation Construction Kit 3D ) ***********************/
  2. /*             Build Current Viewport                     */
  3. /* CopyRight (c) 1993       Author: Lary Myers                     */
  4. /*****************************************************************************/
  5.  
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <dos.h>
  9. #include <mem.h>
  10. #include <alloc.h>
  11. #include <io.h>
  12. #include <fcntl.h>
  13. #include <time.h>
  14. #include <string.h>
  15. #include <sys\stat.h>
  16. #include "ack3d.h"
  17. #include "ackeng.h"
  18. #include "ackext.h"
  19.  
  20. void draw_col2(int Col,int slice,int dist,int width,int ht,UCHAR far *Wall,UCHAR far *Screen,UCHAR far *PalTable,int LightFlag);
  21. void AckCopyBackground(UCHAR far *scrn,UCHAR far *bkgd,int len,int offset);
  22. void DrawSlices(ACKENG *ae);
  23.  
  24. void FindObject(int xPlayer,int yPlayer,int PlayerAngle,ACKENG *ae);
  25. UINT xRay(int x,int y,int angle,ACKENG *ae);
  26. UINT yRay(int x,int y,int angle,ACKENG *ae);
  27. int FindDoor(int MapPosn,ACKENG *ae);
  28. long long_sqrt(long v);
  29.  
  30. void CheckDoors(ACKENG *ae);
  31.  
  32. extern UCHAR    xLight;
  33. extern UCHAR    yLight;
  34.  
  35. /****************************************************************************
  36. **                                       **
  37. ****************************************************************************/
  38. int AckBuildView(ACKENG *ae)
  39. {
  40.         int        i,j,index,xPlayer,yPlayer,PlayerAngle;
  41.         UINT    xBitmap,yBitmap,BitmapNumber;
  42.         int        ViewAngle;
  43.         int        DoorOpenColumn;
  44.         long    xDistance,yDistance;
  45.         long    WallDistance;
  46.         int        distance,LightAdj;
  47.         UINT    BitmapColumn,yBitmapColumn;
  48.         int        OldMapPosn,OldMapPosn1;
  49.         long    xd,yd;
  50.         UINT    offset;
  51.  
  52. CheckDoors(ae);
  53. xPlayer = ae->xPlayer;
  54. yPlayer = ae->yPlayer;
  55. PlayerAngle = ae->PlayerAngle;
  56.  
  57. /* Begin looking 30 degrees to the left of our current angle */
  58. ViewAngle = PlayerAngle - INT_ANGLE_30;
  59.  
  60. if (ViewAngle < 0)
  61.     ViewAngle += INT_ANGLE_360;
  62.  
  63. MaxDistance = 0;
  64. LightAdj = 0;
  65.  
  66. /* Cast two rays for each column of the video display */
  67.  
  68. for (i = 0; i < VIEW_WIDTH; i++)
  69.     {
  70.     WallDistance = 3000000;    /* Set to a ridiculous distance */
  71.     BitmapColumn = -1;        /* Set to no walls found    */
  72.  
  73. /* Don't even cast an X ray if impossible to intersect the X walls */
  74.     if (ViewAngle != INT_ANGLE_90 && ViewAngle != INT_ANGLE_270)
  75.     {
  76.     BitmapNumber = xRay(xPlayer,yPlayer,ViewAngle,ae);
  77.  
  78.     if (BitmapNumber)    /* A wall was found */
  79.         {
  80.         /* Use the Y intercept to determine the wall column */
  81.         BitmapColumn = (LastY1 >> FP_SHIFT) & 0x3F;
  82.  
  83.         /* Keep the orientation the same no matter which side we're on */
  84.         if ((int)iLastX < xPlayer)
  85.         BitmapColumn = 63 - BitmapColumn;
  86.  
  87.         /* Did we strike a door? */
  88.         if ((BitmapNumber & 0xFF) == DOOR_XCODE)
  89.         {
  90.         index = FindDoor(xMapPosn,ae);
  91.         if (index >= 0)                /* This is a valid door */
  92.             {
  93.             j = ae->Door[index].ColOffset;  /* Get its current pos  */
  94.             offset = 0;
  95.  
  96.         if (BitmapNumber & DOOR_TYPE_SLIDE)
  97.             {
  98.             DoorOpenColumn = 63;
  99.             if ((int)iLastX > xPlayer)        /* Handle orientation   */
  100.             j = -j;
  101.             BitmapColumn += j;            /* Adjust column to show */
  102.             }
  103.  
  104.         if (BitmapNumber & DOOR_TYPE_SPLIT)
  105.             {
  106.             DoorOpenColumn = 31;
  107.             if (BitmapColumn < 32)
  108.             {
  109.             BitmapColumn += j;
  110.             if (BitmapColumn > 31)
  111.                 offset = 1;
  112.             }
  113.             else
  114.             {
  115.             BitmapColumn -= j;
  116.             if (BitmapColumn < 32)
  117.                 offset = 1;
  118.             }
  119.  
  120.             }
  121.  
  122.  
  123.             if (offset == 1 || BitmapColumn > 63)
  124.             {
  125.             /* Get the grid coordinates for this door */
  126.             OldMapPosn = ae->Door[index].mPos;
  127.             OldMapPosn1 = ae->Door[index].mPos1;
  128.  
  129.             /* Fake the engine into thinking no door is there */
  130.             ae->xGrid[OldMapPosn] = 0;
  131.             ae->xGrid[OldMapPosn1] = 0;
  132.  
  133.             /* Cast the ray to get walls beyond the door */
  134.             BitmapNumber = xRay(xPlayer,yPlayer,ViewAngle,ae);
  135.  
  136.             /* Put back the door codes if not fully open */
  137.             if (ae->Door[index].ColOffset < DoorOpenColumn)
  138.                 {
  139.                 ae->xGrid[OldMapPosn] = ae->Door[index].mCode;
  140.                 ae->xGrid[OldMapPosn1] = ae->Door[index].mCode1;
  141.                 }
  142.  
  143.             /* Calc the new bitmap column of wall behind door */
  144.             BitmapColumn = (LastY1 >> FP_SHIFT) & 0x3F;
  145.             if ((int)iLastX < xPlayer)
  146.                 BitmapColumn = 63 - BitmapColumn;
  147.             }
  148.             }
  149.         }
  150.  
  151.         /* Calculate the distance to the wall. Since the X position was  */
  152.         /* fixed to move 64 or -64 we can use it to determine the actual */
  153.         /* wall distance. The InvCosTable values were stored with a fixed */
  154.         /* point of 20 decimal places. At this time we'll knock off 14 of */
  155.         /* them so we can later multiply with a fixed point value of 16   */
  156.         xd = iLastX - xPlayer;
  157.         WallDistance = (xd * InvCosTable[ViewAngle]) >> 14;
  158.  
  159.         /* Still looking for the reason this may occur. But this check  */
  160.         /* will force the distance to a ridiculous value so no wall is  */
  161.         /* seen later on when the X and Y walls are compared.        */
  162.         if (WallDistance < 0)
  163.         WallDistance = 120000L;
  164.  
  165.         LightAdj = xLight;
  166.         }
  167.  
  168.     }
  169.  
  170. /* Don't cast a Y ray if its impossible to intercept any Y walls */
  171.     if (ViewAngle != 0 && ViewAngle != INT_ANGLE_180)
  172.     {
  173.     yBitmap = yRay(xPlayer,yPlayer,ViewAngle,ae);
  174.  
  175.     if (yBitmap)        /* A wall was found */
  176.         {
  177.  
  178.         /* Use the X intercept to determine the column of the bitmap */
  179.         yBitmapColumn = (LastX1 >> FP_SHIFT) & 0x3F;
  180.  
  181.         /* Handle orientation from either side of the wall */
  182.         if ((int)iLastY > yPlayer)
  183.         yBitmapColumn = 63 - yBitmapColumn;
  184.  
  185.         /* Did we strike a door? */
  186.         if ((yBitmap & 0xFF) == DOOR_YCODE)
  187.         {
  188.         index = FindDoor(yMapPosn,ae);
  189.         if (index >= 0)            /* This is a valid door */
  190.             {
  191.             /* Get the current door column offset */
  192.             j = ae->Door[index].ColOffset;
  193.             offset = 0;
  194.  
  195.             /* Deal with orientation */
  196.  
  197.         if (yBitmap & DOOR_TYPE_SLIDE)
  198.             {
  199.             DoorOpenColumn = 63;
  200.             if ((int)iLastY < yPlayer)
  201.             j = -j;
  202.             yBitmapColumn += j;
  203.             }
  204.  
  205.         if (yBitmap & DOOR_TYPE_SPLIT)
  206.             {
  207.             DoorOpenColumn = 31;
  208.             if (yBitmapColumn < 32)
  209.             {
  210.             yBitmapColumn += j;
  211.             if (yBitmapColumn > 31)
  212.                 offset = 1;
  213.             }
  214.             else
  215.             {
  216.             yBitmapColumn -= j;
  217.             if (yBitmapColumn < 32)
  218.                 offset = 1;
  219.             }
  220.             }
  221.  
  222.             /* If beyond width of bitmap than cast again */
  223.             if (offset == 1 || yBitmapColumn > 63)
  224.             {
  225.  
  226.             /* Get the yGrid coordinates for this door */
  227.             OldMapPosn = ae->Door[index].mPos;
  228.             OldMapPosn1 = ae->Door[index].mPos1;
  229.  
  230.             /* Fool the engine into thinking no door is there */
  231.             ae->yGrid[OldMapPosn] = 0;
  232.             ae->yGrid[OldMapPosn1] = 0;
  233.  
  234.             /* Cast again for walls beyond the door */
  235.             yBitmap = yRay(xPlayer,yPlayer,ViewAngle,ae);
  236.  
  237.             /* Put door code back if not fully open */
  238.             if (ae->Door[index].ColOffset < DoorOpenColumn)
  239.                 {
  240.                 ae->yGrid[OldMapPosn] = ae->Door[index].mCode;
  241.                 ae->yGrid[OldMapPosn1] = ae->Door[index].mCode1;
  242.                 }
  243.  
  244.             /* Get the bitmap column of wall beyond door */
  245.             yBitmapColumn = (LastX1 >> FP_SHIFT) & 0x3F;
  246.             if ((int)iLastY > yPlayer)
  247.                 yBitmapColumn = 63 - yBitmapColumn;
  248.  
  249.             }
  250.             }
  251.         }
  252.  
  253.  
  254.         /* Calculate the distance to the wall. Since the Y position was  */
  255.         /* fixed to move 64 or -64 we can use it to determine the actual */
  256.         /* wall distance. The InvSinTable values were stored with a fixed */
  257.         /* point of 20 decimal places. At this time we'll knock off 14 of */
  258.         /* them so we can later multiply with a fixed point value of 16   */
  259.         yd = iLastY - yPlayer;
  260.         yDistance = (yd * InvSinTable[ViewAngle]) >> 14;
  261.  
  262.         /* Don't know the reason but change negative value into ridiculous */
  263.         if (yDistance < 0)
  264.         yDistance = 120000L;
  265.  
  266.         /* At this point check the distance to the Y wall against the X */
  267.         /* wall to see which one is closer. The closer one is the one   */
  268.         /* we'll draw at this column of the screen.                     */
  269.         if (yDistance < WallDistance)
  270.         {
  271.         WallDistance = yDistance;
  272.         BitmapNumber = yBitmap;
  273.         BitmapColumn = yBitmapColumn;
  274.         LightAdj = yLight;
  275.         }
  276.  
  277.         }
  278.  
  279.     }
  280.  
  281.     if (BitmapColumn < 64)    /* A wall was found (either X or Y) */
  282.     {
  283.  
  284.     /* To avoid a fishbowl affect we need to adjust the distance so */
  285.     /* it appears perpendicular to the center point of the display    */
  286.     /* which is relative angle 0 from the players current angle. We */
  287.     /* started at -30 degrees for the first screen column and will    */
  288.     /* cycle from -30 down to 0 then back up to +30 degrees. This    */
  289.     /* cosine value was pre-calculated and placed in ViewCosTable.    */
  290.     WallDistance *= ViewCosTable[i];
  291.  
  292.     /* Now we strip off somemore decimal points and check round-up    */
  293.     xd = WallDistance >> 14;
  294.     if (WallDistance - (xd << 14) >= 8096)
  295.         xd++;
  296.  
  297.     /* The last decimal points from the multiplication after the X and */
  298.     /* Y rays is stripped off and checked for round-up.           */
  299.     WallDistance = xd >> 6;
  300.     if (xd - (WallDistance << 6) >= 32)
  301.         WallDistance++;
  302.  
  303.     /* Don't really need to, but put it into an integer for fast compare */
  304.     distance = WallDistance;
  305.  
  306.     /* This is an arbitrary minimum distance to look for */
  307.     if (distance < 10)
  308.         distance = 10;
  309.  
  310.     /* Don't want it to go outside our table boundaries */
  311.     if (distance >= MAX_DISTANCE)
  312.         distance = MAX_DISTANCE - 1;
  313.  
  314.     /* Save the wall data to display when done with entire screen */
  315.     Walls[i].Distance = distance;
  316.     Walls[i].Number = BitmapNumber & 0xFF;
  317.     Walls[i].Column = BitmapColumn;
  318.     Walls[i].LightAdj = LightAdj;
  319.  
  320.     if (distance > MaxDistance)
  321.         MaxDistance = distance;
  322.     }
  323.  
  324.     ViewAngle++;
  325.     if (ViewAngle >= INT_ANGLE_360)
  326.     ViewAngle -= INT_ANGLE_360;
  327.  
  328.     }
  329.  
  330. DrawSlices(ae);
  331.  
  332. /* Now we look at any objects that may be closer than the walls */
  333. FindObject(xPlayer,yPlayer,PlayerAngle,ae);
  334.  
  335. return(0);
  336. }
  337.  
  338.  
  339. /****************************************************************************
  340. **                                       **
  341. ****************************************************************************/
  342. void DrawSlices(ACKENG *ae)
  343. {
  344.     int        i,x1,wt,ht,LightFlag;
  345.     UCHAR   far *wall,*ScreenBuffer;
  346.     UCHAR   far *pTable;
  347.     UCHAR   far **bmaps;
  348.  
  349. AckCopyBackground(ae->ScreenBuffer,ae->BkgdBuffer,ae->WinLength,ae->WinStartOffset);
  350.  
  351. x1 = ae->WinEndX;
  352.  
  353. ht = ae->CenterRow;
  354. wt = BYTES_PER_ROW;
  355. ScreenBuffer = ae->ScreenBuffer;
  356. bmaps = ae->bMaps;
  357. pTable = ae->PalTable;
  358. LightFlag = ae->LightFlag;
  359.  
  360. for (i = ae->WinStartX; i < x1; i++)
  361.     {
  362.     wall = AckGetBitmapPtr(Walls[i].Number,bmaps);
  363.     draw_col2(i,Walls[i].Column,Walls[i].Distance,wt,ht,wall,
  364.           ScreenBuffer,pTable,LightFlag);
  365.     }
  366. }
  367.  
  368.  
  369. /****************************************************************************
  370. **                                       **
  371. ****************************************************************************/
  372. void FindObject(int xPlayer,int yPlayer,int PlayerAngle,ACKENG *ae)
  373. {
  374.     int        i,j,count,SaveCenter;
  375.     int        ObjX,ObjY,ObjNum;
  376.     int        NewX,NewY,LightFlag;
  377.     int        MaxOpp,Column,ColBeg,ColEnd;
  378.     int        wt,ObjIndex,CenterColumn;
  379.     int        vidwt,vidht;
  380.     long    deltax,deltay;
  381.     long    xp,yp,distance;
  382.     long    SinValue,CosValue;
  383.     UCHAR   far *wall,*ScreenBuffer;
  384.     UCHAR   far *pTable;
  385.     UCHAR   far **omaps;
  386.  
  387.     char    mBuf[40];
  388.  
  389. vidht = ae->CenterRow;
  390. vidwt = BYTES_PER_ROW;
  391. ScreenBuffer = ae->ScreenBuffer;
  392. omaps = ae->oMaps;
  393.  
  394.  
  395. TotalObjects = 0;
  396. ObjRelDist[0] = 0L;
  397. SinValue = SinTable[PlayerAngle];
  398. CosValue = CosTable[PlayerAngle];
  399.  
  400. /* First thing we'll do is check all the objects to see which ones may be */
  401. /* completely out of view, and to get some initial values for later...      */
  402. for (i = 0; i < MAX_OBJECTS; i++)
  403.     {
  404.     if (!ae->ObjList[i].Active)
  405.     continue;
  406.  
  407.     ObjX = ae->ObjList[i].x;
  408.     ObjY = ae->ObjList[i].y;
  409.  
  410. /* Translate the object coordinates to make relative to the POV */
  411.     NewX = ObjX - xPlayer;
  412.     NewY = ObjY - yPlayer;
  413.  
  414.     if (abs(NewX) < 10 && abs(NewY) < 10)
  415.     continue;
  416.  
  417.  
  418. #if 0
  419.     if (PlayerAngle > INT_ANGLE_180 && (NewY-63) > 0)
  420.     continue;
  421.  
  422.     if (PlayerAngle < INT_ANGLE_180 && (NewY+63) < 0)
  423.     continue;
  424.  
  425.     if (PlayerAngle > INT_ANGLE_270 || PlayerAngle < INT_ANGLE_90)
  426.     {
  427.     if ((NewX+63) < 0)
  428.         continue;
  429.     }
  430.  
  431.     if (PlayerAngle < INT_ANGLE_270 && PlayerAngle > INT_ANGLE_90)
  432.     {
  433.     if ((NewX-63) > 0)
  434.         continue;
  435.     }
  436. #endif
  437.  
  438.     if ((PlayerAngle == 0 || PlayerAngle == INT_ANGLE_180) && abs(NewX) < 2)
  439.     continue;
  440.  
  441.     if ((PlayerAngle == INT_ANGLE_90 || PlayerAngle == INT_ANGLE_270) &&
  442.     abs(NewY) < 2)
  443.     continue;
  444.  
  445.  
  446.  
  447. /* Rotate coordinates to current player angle */
  448.     xp = ((NewX * CosValue) + (NewY * SinValue)) >> FP_SHIFT;
  449.     yp = ((NewY * CosValue) - (NewX * SinValue)) >> FP_SHIFT;
  450.  
  451.     if (xp <= 0)
  452.     continue;
  453.  
  454.     distance = (long)long_sqrt((xp * xp) + (yp * yp));
  455.  
  456.     if (distance >= MAX_DISTANCE)
  457.     continue;
  458.  
  459. /* Place the objects in the correct order so further ones are behind */
  460.     j = TotalObjects;
  461.     if (j)
  462.     {
  463.     for (count = 0; count < TotalObjects; count++)
  464.         {
  465.         if (distance > ObjRelDist[count])
  466.         {
  467.         for (j = TotalObjects; j > count; j--)
  468.             {
  469.             ObjRelDist[j] = ObjRelDist[j-1];
  470.             ObjNumber[j]  = ObjNumber[j-1];
  471.             ObjDeltaX[j]  = ObjDeltaX[j-1];
  472.             ObjDeltaY[j]  = ObjDeltaY[j-1];
  473.             }
  474.  
  475.         j = count;
  476.         count = TotalObjects;
  477.         }
  478.         }
  479.     }
  480. /* Hold onto relavant data for the object found */
  481.     ObjNumber[j]  = i;
  482.     ObjRelDist[j] = distance;
  483.     ObjDeltaX[j] = xp;
  484.     ObjDeltaY[j] = yp;
  485.     TotalObjects++;
  486.     ObjRelDist[TotalObjects] = 0L;
  487.     }
  488.  
  489. /* Didn't find any objects on the above pass, so we're done */
  490. if (!TotalObjects)
  491.     return;
  492.  
  493. CenterColumn = ae->WinStartX + (ae->WinWidth / 2);
  494.  
  495. pTable = ae->PalTable;
  496. LightFlag = ae->LightFlag;
  497.  
  498. for (i = 0; i < TotalObjects; i++)
  499.     {
  500.     ObjIndex = ObjNumber[i];
  501.     ObjNum = ae->ObjList[ObjIndex].bmNum[ae->ObjList[ObjIndex].CurNum];
  502.  
  503.     ObjY = ae->ObjList[ObjIndex].y;
  504.     NewY = ObjY - yPlayer;
  505.  
  506.     distance = ObjRelDist[i];
  507.     deltax   = ObjDeltaX[i];
  508.     yp = deltay = ObjDeltaY[i];
  509.  
  510.     MaxOpp = ((LongTanTable[INT_ANGLE_30] * (long)deltax) >> FP_SHIFT);
  511.  
  512.     if (NewY < ObjY)
  513.     {
  514.     MaxOpp = -MaxOpp;
  515.     yp = -yp;
  516.     }
  517.  
  518.     if ((yp+32) < MaxOpp)
  519.     continue;
  520.  
  521.     Column = CenterColumn;
  522.  
  523.     if (MaxOpp)
  524.     Column = CenterColumn - ((deltay * CenterColumn) / MaxOpp);
  525.  
  526.     yp = ViewCosTable[Column];
  527.     if (yp)
  528.     {
  529.     distance = distance * yp;
  530.  
  531.     xp = distance >> 14;
  532.     if (distance - (xp << 14) >= 8096)
  533.         xp++;
  534.  
  535.     distance = xp;
  536.     }
  537.  
  538.     if (distance < 0)
  539.     continue;
  540.  
  541.     if (distance >= (MAX_DISTANCE - 10))
  542.     distance = MAX_DISTANCE-11;
  543.  
  544.     wt = DistanceTable[distance];
  545.  
  546. /* Keep the width of the object reasonable */
  547.  
  548.     if (wt > 300)
  549.     continue;
  550.  
  551.     if (wt < 16) wt = 16;
  552.  
  553. #if 0
  554.     if (wt > 300) wt = 300;
  555. #endif
  556.  
  557.     yp = AdjustTable[distance];
  558.     xp = 0;            /* First col of the object to display */
  559.  
  560. #if 0
  561.     wt >>= 1;
  562. #endif
  563.  
  564.     NewX = Column;
  565.  
  566.     if (ae->ObjList[ObjIndex].Sides)
  567.     ObjNum =
  568.      ae->ObjList[ObjIndex].bmNum[((PlayerAngle / ae->ObjList[ObjIndex].Sides) & 7)];
  569.  
  570.     SaveCenter = ae->CenterRow;
  571.     ae->CenterRow = ae->ObjList[ObjIndex].VidRow;
  572.     ColEnd = NewX + wt;
  573.  
  574.     for (Column = NewX - wt; Column < ColEnd; Column++)
  575.     {
  576.     if (Column >= ae->WinStartX && Column <= ae->WinEndX)
  577.         {
  578.         if (distance < (Walls[Column].Distance + 10))
  579.         {
  580.         wall = AckGetBitmapPtr(ObjNum,omaps);
  581.  
  582.         draw_col2(Column,xp >> FP_SHIFT,distance,vidwt,vidht,wall,
  583.               ScreenBuffer,pTable,LightFlag);
  584.         }
  585.  
  586.         }
  587.     xp += yp;   /* Advance the next column to display (scaling) */
  588.     }
  589.  
  590.     ae->CenterRow = SaveCenter;
  591.     }
  592.  
  593. }
  594.  
  595.  
  596.